#pragma once

#include "Log.hpp"
#include <string>
#include <cstring>
#include <jsoncpp/json/json.h>

namespace ns_protocol
{
    class Request
    {
#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define SEP "\r\n"
#define SEP_LEN strlen(SEP)

    public:
        Request() {}

        Request(int x, int y, char op)
            : _x(x), _y(y), _op(op)
        {
        }

        // 序列化协议：_x op _y
        std::string serialize()
        {
#ifdef MYSELF
            std::string ser; // 序列化后的结果
            ser += std::to_string(_x);
            ser += SPACE;
            ser += _op;
            ser += SPACE;
            ser += std::to_string(_y);
            return ser;
#else
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;

            Json::FastWriter writer;
            return writer.write(root);
#endif
        }

        // 反序列化
        bool deserialize(const std::string &s)
        {
#ifdef MYSELF
            // 提取第一个SPACE，进而提取做操作数
            size_t left_space = s.find(SPACE);
            if (left_space == std::string::npos)
                return false;
            else
                _x = std::stoi(s.substr(0, left_space));

            // 查找后面的SPACE，进而提取右操作数
            size_t right_space = s.rfind(SPACE);
            if (right_space == std::string::npos)
                return false;
            else
                _y = std::stoi(s.substr(right_space + SPACE_LEN));

            // 提取操作符
            _op = s[left_space + SPACE_LEN];

            return true;
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(s, root);

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt();

            return true;
#endif
        }

        int _x;   // 做操作数
        int _y;   // 右操作数
        char _op; // 操作符
    };

    class Reponse
    {
#define SPACE " "
#define SPACE_LEN strlen(SPACE)

    public:
        Reponse(int flag = 0, int result = 0)
            : _flag(flag), _result(result)
        {
        }

        // 序列化协议：_flag _result
        std::string serialize()
        {
#ifdef MYSELF
            std::string ser;
            ser += std::to_string(_flag);
            ser += SPACE;
            ser += std::to_string(_result);
            return ser;
#else
            Json::Value root;
            root["flag"] = _flag;
            root["result"] = _result;

            Json::FastWriter writer;
            return writer.write(root);
#endif
        }

        // 反序列化
        bool deserialize(const std::string &s)
        {
#ifdef MYSLEF
            size_t pos = s.find(SPACE);
            if (pos == std::string::npos)
                return false;
            else
                _flag = std::stoi(s.substr(0, pos));

            _result = std::stoi(s.substr(pos + SPACE_LEN));
            return true;

#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(s, root);

            _flag = root["flag"].asInt();
            _result = root["result"].asInt();

            return true;
#endif
        }

        int _flag;   // 运算是否成功的标识
        int _result; // 运算结果
    };

    // 编码函数
    // length/n/r_x op _y/n/r
    std::string EnCode(const std::string &s)
    {
        int length = s.size();
        std::string ret(std::to_string(length));
        ret += SEP;
        ret += s;
        ret += SEP;
        // logMessage(NORMAL, "EnCode: %s\n", ret.c_str());
        return ret;
    }

    // 解码函数
    std::string DeCode(std::string &s)
    {
        auto pos = s.find(SEP);
        if (pos == std::string::npos)
            return "";

        int size_content = stoi(s.substr(0, pos)); // 正文长度

        // 检查剩余长度是否满足要求：size_content + SEP_LEN
        if (s.size() - pos - 2 * SEP_LEN >= size_content)
        {
            s.erase(0, pos + SEP_LEN);
            std::string ret = s.substr(0, size_content);
            s.erase(0, size_content + SEP_LEN);
            // logMessage(NORMAL, "DeCode:%s\n", ret.c_str());
            return ret;
        }

        return "";
    }
}